package com.lidong.lowcode.database.init.postgresql;

import com.lidong.lowcode.database.constants.BaseConst;
import com.lidong.lowcode.database.constants.MetaDataConst;
import com.lidong.lowcode.database.entity.database.DataBaseColumn;
import com.lidong.lowcode.database.entity.database.DataBaseIndex;
import com.lidong.lowcode.database.entity.database.DataBasePrimaryKey;
import com.lidong.lowcode.database.entity.database.DataBaseTable;
import com.lidong.lowcode.database.init.core.DataBaseMetaDataHandle;
import com.lidong.lowcode.database.init.core.InitDataBaseContext;

import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author LiDong
 * @version 1.0.0
 * @createTime 12/1/2022 9:05 PM
 */
public class PostGreSqlMetaDataHandle extends DataBaseMetaDataHandle {

    public PostGreSqlMetaDataHandle(InitDataBaseContext initDataBaseContext) {
        super(initDataBaseContext);
    }

    /**
     * Mysql 元数据表解析
     *
     * @return List
     * @throws SQLException SQLException
     */
    @Override
    protected List<DataBaseTable> getDataBaseTableList() throws SQLException {
        List<DataBaseTable> tableList = new ArrayList<>();
        String schema = this.getSchema();
        String sql = "select * from information_schema.tables where table_schema='" + schema + BaseConst.SINGLE_QUOTES;
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
        for (Map<String, Object> map : list) {
            DataBaseTable dataBaseTable = new DataBaseTable();
            String tableName = (String) map.get(MetaDataConst.U_TABLE_NAME);
            dataBaseTable.setTableName(tableName);
            tableList.add(dataBaseTable);
        }
        return tableList;
    }

    /**
     * Mysql 元数据字段解析
     *
     * @param dataBaseTableList 元数据表
     */
    @Override
    public void getColumnList(List<? extends DataBaseTable> dataBaseTableList) throws SQLException {
        String schema = this.getSchema();
        String sql = "select * from information_schema.columns where table_schema ='" + schema + "'";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
        Map<Object, List<Map<String, Object>>> columnMap = list.stream().collect(Collectors.groupingBy(x -> x.get(MetaDataConst.U_TABLE_NAME)));
        for (DataBaseTable dataBaseTable : dataBaseTableList) {
            String tableName = dataBaseTable.getTableName();
            List<DataBaseColumn> dataBaseColumnList = new ArrayList<>();
            List<Map<String, Object>> columnList = Optional.ofNullable(columnMap.get(tableName)).orElse(Collections.emptyList());
            for (Map<String, Object> map : columnList) {
                DataBaseColumn dataBaseColumn = new DataBaseColumn();
                String columnName = (String) map.get(MetaDataConst.U_COLUMN_NAME);
                dataBaseColumn.setName(columnName);
                dataBaseColumnList.add(dataBaseColumn);
            }
            dataBaseTable.setColumnList(dataBaseColumnList);
        }
    }

    /**
     * 获取元数据索引信息主键和索引
     *
     * @param dataBaseTableList 元数据表
     * @throws SQLException SQLException
     */
    @Override
    protected void getIndexList(List<? extends DataBaseTable> dataBaseTableList) throws SQLException {
        String sql = "select * from information_schema.statistics where table_schema = '" + this.getSchema() + "'";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
        Map<Object, List<Map<String, Object>>> indexMap = list.stream().collect(Collectors.groupingBy(x -> x.get(MetaDataConst.U_TABLE_NAME)));
        for (DataBaseTable dataBaseTable : dataBaseTableList) {
            String tableName = dataBaseTable.getTableName();
            List<Map<String, Object>> indexMapList = Optional.ofNullable(indexMap.get(tableName)).orElse(Collections.emptyList());

            // 非主键索引
            List<Map<String, Object>> tempIndexMapList = indexMapList.stream().filter(x -> !MetaDataConst.U_PRIMARY.equals(x.get(MetaDataConst.U_INDEX_NAME))).collect(Collectors.toList());
            Map<Object, List<Map<String, Object>>> indexNameMap = tempIndexMapList.stream().collect(Collectors.groupingBy(x -> x.get(MetaDataConst.U_INDEX_NAME)));
            List<DataBaseIndex> indexList = new ArrayList<>();
            for (Map.Entry<Object, List<Map<String, Object>>> entry : indexNameMap.entrySet()) {
                Object indexName = entry.getKey();
                DataBaseIndex dataBaseIndex = new DataBaseIndex();
                dataBaseIndex.setName((String) indexName);
                List<Map<String, Object>> tempIndexList = entry.getValue();
                List<DataBaseColumn> dataBaseColumnList = new ArrayList<>();
                for (Map<String, Object> map : tempIndexList) {
                    String columnName = (String) map.get(MetaDataConst.U_COLUMN_NAME);
                    DataBaseColumn dataBaseColumn = new DataBaseColumn();
                    dataBaseColumn.setName(columnName);
                    dataBaseColumnList.add(dataBaseColumn);
                }
                dataBaseIndex.setColumns(dataBaseColumnList);
                indexList.add(dataBaseIndex);
            }
            dataBaseTable.setIndexList(indexList);

            // 主键索引
            List<Map<String, Object>> primaryKeyMapList = indexMapList.stream().filter(x -> MetaDataConst.U_PRIMARY.equals(x.get(MetaDataConst.U_INDEX_NAME))).collect(Collectors.toList());
            DataBasePrimaryKey primaryKey = new DataBasePrimaryKey();
            List<DataBaseColumn> primaryKeyColumnList = new ArrayList<>();
            for (Map<String, Object> map : primaryKeyMapList) {
                String columnName = (String) map.get(MetaDataConst.U_COLUMN_NAME);
                DataBaseColumn dataBaseColumn = new DataBaseColumn();
                dataBaseColumn.setName(columnName);
                primaryKeyColumnList.add(dataBaseColumn);
            }
            primaryKey.setColumns(primaryKeyColumnList);
            dataBaseTable.setPrimaryKey(primaryKey);
        }
    }
}
